/*
Copyright (c) 2012 Yathindu Rangana
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef OGRE_FACE_H
#define OGRE_FACE_H

#include "Simpleton.h"
#include "sm_api.h"
#include "lock.h"
#include "EventListener.h"
#include "Event.h"
#include "EventManager.h"
#include "DataEvent.h"

using namespace sm::faceapi::samplecode;

/** Based on a error code will throw a run-time exception
	
	@param	x	Error code
*/
#define THROW_ON_ERROR(x) \
{ \
    smReturnCode result = (x); \
    if (result < 0) \
    { \
        std::stringstream s; \
        s << "API error code: " << result; \
        throw std::runtime_error(s.str()); \
    } \
}
/**
	Initialises and destroys FaceAPI data structures
	Register with this class to receive face tracking update events
*/
class OgreFace: public Simpleton<OgreFace>
{
public:
	/**
		Defines the 3D pose of the head.
	*/
	struct HeadPose
	{
		Ogre::Vector3		Position;		//< Position of the head relative to the camera 
		Ogre::Vector3		PitchYawRoll;	//< Rotation of the head around the X,Y and Z axes respectively in euler angles
		Ogre::Quaternion	Orientation;	//< Rotation of the head expressed as a Quaternion
		Ogre::Real			Confidence;		//< Confidence of the head-pose measurement [0..1]. A value of 0 indicates that the measurements cannot be trusted and may have undefined values. 
		Ogre::Vector3		LeftEyePos;		//< Position of the left eyeball center relative to the camera.
		Ogre::Vector3		RightEyePos;	//< Position of the right eyeball center relative to the camera. 
	};

	/**
		Adds your class to the listener registry.
		
		@param	eventListener	The listener to add
	*/
	void addListener(EventSystem::EventListener& eventListener);

	/**
		Remove a listener from the registry
		
		@param	eventListener	The listener to remove
	*/
	void removeListener(EventSystem::EventListener& eventListener){ m_EventManager.removeListener(eventListener); }
private:
	OgreFace();
	~OgreFace();

	void static _stdcall receiveLogMessage(void *, const char *buf, int /*buf_len*/)
	{
		Lock lock(s_mutex); // serialize logging calls from different threads to avoid garbled output.
		Ogre::LogManager::getSingletonPtr()->logMessage(buf);
	}
	void static _stdcall receiveHeadPose(void *,smEngineHeadPoseData head_pose, smCameraVideoFrame video_frame);
	friend class Simpleton< OgreFace >;

	static Mutex s_mutex;

	//face track vars
	smEngineHandle engine_handle;	//< FaceAPI engine
	smVideoDisplayHandle video_display_handle;	//< The debug video window @note this I think is not destroyed properly at shutdown
	smEngineHeadPoseData	m_head_pose; //< The latest headpose from FaceAPI

	//event system
	static EventSystem::EventManager m_EventManager;
};

#endif